#pragma once
#include "LPHTTPHeader.h"
namespace LocalProxy
{
#pragma warning(push)
#pragma warning(disable:4996 )
	class CHTTPResponse
	{
	public:		
		static const char *PROTOCOL_VER_STR[];
		static const char *CRLF;
		static const char *SP;protected:
	protected:
		typedef CAtlArray<CHTTPHeaderLine*> _HTTPHeader;
		static const size_t LINE_MAX_SIZE=4096;
	public:
		CHTTPResponse()
			:m_ulResponseCoce(0)
			,m_pContentLength(NULL)
			,m_pHost(NULL)
			,m_pConnection(NULL)
			,m_ProtocolVersion(PV_HTTP_1_1)
		{}

		virtual ~CHTTPResponse()
		{
			Reset();
		}

		virtual void Reset()
		{
			CHTTPHeaderLine** ppData=m_HTTPHeader.GetData();
			size_t n=m_HTTPHeader.GetCount();
			for(size_t i=0;i<n;i++)
			{
				delete ppData[i];
			}
			m_HTTPHeader.RemoveAll();
		
			m_ProtocolVersion=PV_HTTP_1_1;
			m_pContentLength=NULL;
			m_pHost=NULL;
			m_pConnection=NULL;
		}

		ULONG GetContentLength() const
		{
			if(!m_pContentLength)
			{
				return 0;
			}
			return m_pContentLength->GetContentLength();
		}

		ConnectionType GetConnection() const
		{
			if(m_pConnection)
			{
				return m_pConnection->GetConnection();
			}
			return CT_Unknow;
		}

		void AppendToDbgBuf(char c)
		{
			m_dbgBuf.Append(&c,1);
		}

		CAtlIsapiBuffer<> m_dbgBuf;
	protected:
		_HTTPHeader m_HTTPHeader;
		PROTOCOL_VER m_ProtocolVersion;
		CHTTPHeaderContentLength *m_pContentLength;
		CHTTPHeaderHost *m_pHost;
		CHTTPHeaderConnection *m_pConnection;
		ULONG m_ulResponseCoce;
		CString m_sResponseTip;
	};

	__declspec(selectany)
		const char *CHTTPResponse::PROTOCOL_VER_STR[]={
			"HTTP/1.0",
			"HTTP/1.1",
			"UNKNOW",	
	};
	__declspec(selectany)
		const char *CHTTPResponse::CRLF="\r\n";
	__declspec(selectany)
		const char *CHTTPResponse::SP=" ";

	class CHTTPResponseParser
		:public CHTTPResponse
	{
		enum PARSE_STEP{
			PS_HEADER_FIRST_LINE,
			PS_HEADER,
			PS_DATA,
			PS_OVER,
		};
	public:
		CHTTPResponseParser()
			:m_iCurLineSize(0)
			,m_iLastLineSize(0)
			,m_curPS(PS_HEADER_FIRST_LINE)
			,m_bHeaderEnd(FALSE)
			,m_iCurPostDataSize(0)
		{
			m_pBufLine=new CTempBuffer<BYTE>(LINE_MAX_SIZE+1);
		}

		virtual ~CHTTPResponseParser()
		{
			FreeBuf();
		}

		virtual void Reset()
		{
			CHTTPResponse::Reset();
			m_iCurLineSize=0;
			m_iLastLineSize=0;
			m_curPS=PS_HEADER_FIRST_LINE;
			m_bHeaderEnd=FALSE;
			m_iCurPostDataSize=0;
		}

		BOOL HeaderEnd() const
		{
			return m_bHeaderEnd;
		}

		int Read(LPCH pBuf,int iLen)
		{
			int iCurParse=0;

			switch(m_curPS)
			{
			case PS_HEADER_FIRST_LINE:
				{
					for(;iCurParse<iLen;iCurParse++)
					{
						m_pBufLine[0][m_iCurLineSize++]=pBuf[iCurParse];
						if(m_iCurLineSize>LINE_MAX_SIZE)
						{
							ATLASSERT(0);
							return -1;
						}
						if(m_iCurLineSize>2
							&&(*(SHORT*)(m_pBufLine[0]+m_iCurLineSize-2)==*(SHORT*)CRLF)
							)
						{
							m_curPS=PS_HEADER;
							m_pBufLine[0][m_iCurLineSize-2]=0;
							m_iCurLineSize=0;						
							ParseFirstLine();
							break;
						}
					}
					if(iCurParse>=iLen)
					{
						break;
					}
				}			
			case PS_HEADER:
				{
					for(;iCurParse<iLen;iCurParse++)
					{
						m_pBufLine[0][m_iCurLineSize++]=pBuf[iCurParse];
						if(m_iCurLineSize>LINE_MAX_SIZE)
						{
							ATLASSERT(0);
							return -1;
						}
						if(m_iCurLineSize>=2
							&&(*(SHORT*)(m_pBufLine[0]+m_iCurLineSize-2)==*(SHORT*)CRLF)
							)
						{
							if(m_iCurLineSize==2)
							{								
								m_curPS=PS_OVER;
								m_bHeaderEnd=TRUE;
								return iCurParse+1;								
							}
							else
							{
								CString sName,sContent;
								if(!CHTTPHeaderLine::IsHeaderLine(CString((const char*)(LPBYTE)m_pBufLine[0],static_cast<int>(m_iCurLineSize)),sName,sContent))
								{
									ATLASSERT(0);
								}
								else
								{
									if(CHTTPHeaderContentLength::Match(sName))
									{
										m_pContentLength=new CHTTPHeaderContentLength(sContent);
										m_HTTPHeader.Add(m_pContentLength);										
									}									
									else if(CHTTPHeaderConnection::Match(sName))
									{
										m_pConnection=new CHTTPHeaderConnection(sContent);
										m_HTTPHeader.Add(m_pConnection);
									}									
									else
									{
										CHTTPHeaderLine *p=new CHTTPHeaderLine(sName,sContent);
										m_HTTPHeader.Add(p);
									}
								}
								m_iCurLineSize=0;
							}						
						}
					}
					if(iCurParse>=iLen)
					{
						break;
					}				
				}			
			case PS_DATA:
				{
					ATLASSERT(0);
				}
				break;
			case PS_OVER:
				{

				}
				break;
			default:
				ATLASSERT(0);
			}
			return iCurParse+1;
		}

		int ReadChar(CHAR ch)
		{
			AppendToDbgBuf(ch);
			switch(m_curPS)
			{
			case PS_HEADER_FIRST_LINE:
				{					
					m_pBufLine[0][m_iCurLineSize++]=ch;
					if(m_iCurLineSize>LINE_MAX_SIZE)
					{
						ATLASSERT(0);
						return -1;
					}
					if(m_iCurLineSize>2
						&&(*(SHORT*)(m_pBufLine[0]+m_iCurLineSize-2)==*(SHORT*)CRLF)
						)
					{
						m_curPS=PS_HEADER;
						m_pBufLine[0][m_iCurLineSize-2]=0;
						m_iCurLineSize=0;						
						ParseFirstLine();
						break;
					}
				}	
				break;
			case PS_HEADER:
				{					
					m_pBufLine[0][m_iCurLineSize++]=ch;
					if(m_iCurLineSize>LINE_MAX_SIZE)
					{
						ATLASSERT(0);
						return -1;
					}
					if(m_iCurLineSize>=2
						&&(*(SHORT*)(m_pBufLine[0]+m_iCurLineSize-2)==*(SHORT*)CRLF)
						)
					{
						if(m_iCurLineSize==2)
						{								
							m_curPS=PS_OVER;
							m_bHeaderEnd=TRUE;
							return 1;								
						}
						else
						{
							CString sName,sContent;
							if(!CHTTPHeaderLine::IsHeaderLine(CString((const char*)(LPBYTE)m_pBufLine[0],static_cast<int>(m_iCurLineSize)),sName,sContent))
							{
								ATLASSERT(0);
							}
							else
							{
								if(CHTTPHeaderContentLength::Match(sName))
								{
									m_pContentLength=new CHTTPHeaderContentLength(sContent);
									m_HTTPHeader.Add(m_pContentLength);										
								}									
								else if(CHTTPHeaderConnection::Match(sName))
								{
									m_pConnection=new CHTTPHeaderConnection(sContent);
									m_HTTPHeader.Add(m_pConnection);
								}									
								else
								{
									CHTTPHeaderLine *p=new CHTTPHeaderLine(sName,sContent);
									m_HTTPHeader.Add(p);
								}
							}
							m_iCurLineSize=0;
						}						
					}								
				}
				break;
			case PS_DATA:
				{
					ATLASSERT(0);
				}
				break;
			case PS_OVER:
				{

				}
				break;
			default:
				ATLASSERT(0);
			}
			return 1;
		}

	protected:
		void FreeBuf()
		{
			if(m_pBufLine)
			{
				delete m_pBufLine;
				m_pBufLine=NULL;
			}
		}

		BOOL ParseFirstLine()
		{
#define PARSE_METHOD(ret,def,str)\
	if(ret==RM_UNKNOW&&strnicmp(str,REQUEST_METHOD_STR[def],sizeof(REQUEST_METHOD_STR[def])-1)==0){ret=def;}
			char *_Context=NULL;
			char *_Term;
			_Term=strtok_s((char *)(LPBYTE)m_pBufLine[0],SP,&_Context);			

			if(strnicmp(_Term,PROTOCOL_VER_STR[PV_HTTP_1_1],sizeof(PROTOCOL_VER_STR[PV_HTTP_1_1])-1)==0)
			{
				m_ProtocolVersion=PV_HTTP_1_1;				
			}
			else
			{
				m_ProtocolVersion=PV_HTTP_1_0;
			}

			_Term=strtok_s(NULL," ",&_Context);

			if(!_Term)
			{
				ATLASSERT(0);
				return FALSE;
			}
			m_ulResponseCoce=(ULONG)atol(_Term);
			//_Term=strtok_s(NULL,"\r\n",&_Context);
			if(!_Context)
			{
				ATLASSERT(0);
				return FALSE;
			}
			m_sResponseTip=CString(_Context);
			return TRUE;
		}
	private:
		CTempBuffer<BYTE> *m_pBufLine;

		size_t m_iCurLineSize;
		size_t m_iLastLineSize;
		size_t m_iCurPostDataSize;
		PARSE_STEP m_curPS;
		BOOL m_bHeaderEnd;
	};
#pragma warning(pop)
}